/*
 * author      : 吴中勤 
 * date        : 2019/3/31
 * description : TODO
 */

package org.wzq.learn.infrastructure.lib.trace;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.lang.reflect.Method;


@Aspect
@Component
public class ExceptionReporterAspect {

    private static final Logger logger = LoggerFactory.getLogger(ExceptionReporterAspect.class);

    /* 对加了 @ResponseStatus  @ExceptionHandler 的进行处理 */
    @After("@annotation(org.springframework.web.bind.annotation.ResponseStatus) && @annotation(org.springframework.web.bind.annotation.ExceptionHandler)")
    public void deduceByAnnotation(JoinPoint joinPoint) {
        if (logger.isInfoEnabled()) logger.info("deduceByAnnotation");
        judgeReport(joinPoint);
    }


    /* 对加了 @EnableErrorReport 的进行处理 */
    @After("@annotation(org.wzq.learn.infrastructure.lib.trace.EnableErrorReport)")
    public void directEnabled(JoinPoint joinPoint) {
        if (logger.isInfoEnabled()) logger.info("directEnabled");
        judgeReport(joinPoint);
    }


    private void judgeReport(JoinPoint joinPoint) {
        try {
            Object[] args = joinPoint.getArgs();

            // 获取 ResponseStatus(优先) 或 EnableErrorReport的值
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            ResponseStatus responseStatus = method.getAnnotation(ResponseStatus.class);
            EnableErrorReport enableErrorReport = method.getAnnotation(EnableErrorReport.class);
            int status = responseStatus != null
                    ? responseStatus.value().value() : enableErrorReport.value().value();

            // 根据规则判断是否发送
            if (!shouldReport(status)) {
                if (logger.isInfoEnabled()) logger.info("not report error, HttpStatus={}", status);
                return;
            }

            if (logger.isInfoEnabled()) logger.info("should report error, HttpStatus={}", status);
            // 找到异常对象
            Throwable throwable = null;
            for (int i = 0; i < args.length; i++) {
                Object obj = args[i];
                if (obj instanceof Throwable) {
                    throwable = (Throwable) obj;
                    break;
                }
            }

            if (throwable != null) {
                ErrorReporter.getInstance().sendAPIError(throwable);
            }
        } catch (Exception ex) {
            logger.error("不影响正常业务 => judgeReport 出错", ex);
            // 忽略
        }
    }

    private boolean shouldReport(int httpStatus) {
        return httpStatus >= HttpStatus.INTERNAL_SERVER_ERROR.value();
    }
}
